//test channel buffer

package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

func print(msg string) {
	fmt.Printf("%s %s\n", time.Now().String(), msg)
}

type Buffer struct {
	Buf   chan string
	Count int
}

func (b *Buffer) Write(str string) {
	b.Buf <- str
	print(fmt.Sprintf("Write str:[%s],count:[%d]", str, b.Count))
	b.Count++

}
func (b *Buffer) Read() {
	print("开始Read")
	for str := range b.Buf {
		print(fmt.Sprintf("Read str:[%s],count:[%d]", str, b.Count))
		b.Count--
	}
}

func test1() {
	var buffer = Buffer{
		Buf:   make(chan string, 20),
		Count: 0,
	}
	go buffer.Read()
	//count := 0
	for {
		delay := rand.Intn(10)
		buffer.Write("aabbccddeeffgghh")
		buffer.Write("aabbccddeeffgghh")

		buffer.Write("aabbccddeeffgghh")
		time.Sleep(time.Duration(delay) * time.Second)
	}
}

//
//
// for test2

var buf2 = make(chan string, 200)

func test2Write() {
	print("test2 Write")
	defer func() {
		print("recover")
		if e := recover(); e != nil {
			fmt.Printf("recover err:%v", e)
		}
	}()
	count := 1
	for {
		str := fmt.Sprintf("str%d", count)
		buf2 <- str
		count++
		print(fmt.Sprintf("test2 Write: %s", str))
		d := time.Duration(rand.Intn(50)) * time.Microsecond
		//time.Sleep(time.Microsecond)
		time.Sleep(d)
	}
}
func test2Read() {
	print("test2 Read")
	b := make([]string, 0)
	d := time.Duration(5) * time.Millisecond
	t := time.NewTimer(d)
	total := 0
	for {
		select {
		case str := <-buf2:
			print(fmt.Sprintf("test2 Read: %s", str))
			b = append(b, str)
			if len(b) == 10 {
				msg := fmt.Sprintf("full b %d:[%s]", len(b), strings.Join(b, ","))
				print(msg)
				b = b[:0]
				print("full  reset")
				t.Stop()
				t = time.NewTimer(d)
				//total++
				// if total > 5 {
				// 	os.Exit(0)
				// }

			}
		case <-t.C:
			msg := fmt.Sprintf("len b %d:[%s]", len(b), strings.Join(b, ","))
			print(msg)
			b = b[:0]
			print("time out reset")
			t.Stop()
			t = time.NewTimer(d)
			total++
			if total > 5 {
				os.Exit(0)
			}
		}
	}

}

func test2() {
	go test2Read()
	test2Write()

}
func main() {
	//test1()
	test2()
}
